package org.lzfto.flink.demo.common.crypto;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Base64;

/**
 * 更安全的AES256-GCM加密实现
 */
public class AESCryptoUtil {
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    private static final int KEY_LENGTH = 256;
    private static final int IV_LENGTH = 12; // GCM推荐12字节
    private static final int TAG_LENGTH = 128; // GCM标签长度
    private static final int ITERATIONS = 10000; // PBKDF2迭代次数
    private static final int SALT_SIZE = 32; // 32字节盐值
    
    private final byte[] salt;
    private final byte[] iv;
    private final SecretKey secretKey;

    public AESCryptoUtil(String password) {
    	this(hexToBytes("415c6e5416998cdcfb3a611c947f3efeaa1689347658087d8e238de4f0b54df8"),password);
    }
    
    public AESCryptoUtil(String salt, String password) {
    	this(hexToBytes(salt),password);
    }
    /**
     * 更安全的构造函数，使用PBKDF2派生密钥
     * @param salt 盐值，长度必须为32字节
     * @param password 额外的密码参数，增强安全性
     */
    public AESCryptoUtil(byte[] salt, String password) {
        if (salt == null || salt.length != SALT_SIZE) {
            throw new IllegalArgumentException("Salt must be 32 bytes");
        }
        this.salt = salt.clone();
        this.iv = new byte[IV_LENGTH];
        System.arraycopy(salt, 0, iv, 0, Math.min(IV_LENGTH, salt.length));
        
        try {
            // 使用PBKDF2派生密钥
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec spec = new PBEKeySpec(password.toCharArray(), this.salt, ITERATIONS, KEY_LENGTH);
            SecretKey tmp = factory.generateSecret(spec);
            this.secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
            
            // 清除敏感数据
            if (password != null) {
                java.util.Arrays.fill(password.toCharArray(), '\0');
            }
        } catch (Exception e) {
            throw new RuntimeException("密钥生成失败", e);
        }
    }

    /**
     * 更安全的加密方法(AES-GCM)
     * @param plainText 明文
     * @return Base64编码的加密结果(格式: IV + 密文 + TAG)
     */
    public String encrypt(String plainText) {
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH, iv);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
            
            byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new RuntimeException("加密失败", e);
        }
    }

    /**
     * 更安全的解密方法(AES-GCM)
     * @param encryptedText Base64编码的加密文本
     * @return 解密后的明文
     */
    public String decrypt(String encryptedText) {
        try {
            byte[] decoded = Base64.getDecoder().decode(encryptedText);
            
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH, iv);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
            
            byte[] decrypted = cipher.doFinal(decoded);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException("解密失败", e);
        }
    }

    /**
     * 生成随机盐值
     * @return 16字节的随机盐值
     */
    /**
     * 生成随机盐值(32字节)
     * @return 32字节的随机盐值
     */
    public static byte[] generateRandomSalt() {
        byte[] salt = new byte[SALT_SIZE];
        new SecureRandom().nextBytes(salt);
        return salt;
    }
    
    /**
     * 生成随机密码(可选)
     * @return 随机生成的密码
     */
    public static String generateRandomPassword() {
        byte[] password = new byte[16];
        new SecureRandom().nextBytes(password);
        return Base64.getEncoder().encodeToString(password);
    }

    /**
     * 将字节数组转换为十六进制字符串
     * @param bytes 要转换的字节数组
     * @return 十六进制表示的字符串
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    /**
     * 将十六进制字符串转换为字节数组
     * @param hexString 十六进制字符串（长度应为偶数）
     * @return 对应的字节数组
     * @throws IllegalArgumentException 如果输入不是有效的十六进制字符串或长度为奇数
     */
    public static byte[] hexToBytes(String hexString) {
        if (hexString == null || hexString.length() % 2 != 0) {
            throw new IllegalArgumentException("Hex string must be non-null and even length");
        }
        
        byte[] bytes = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i += 2) {
            String hex = hexString.substring(i, i + 2);
            bytes[i / 2] = (byte) Integer.parseInt(hex, 16);
        }
        return bytes;
    }
}
